package com.hl.payServer.task;

import com.alibaba.fastjson.JSON;
import com.hl.payServer.model.PayTradeInfo;
import com.hl.payServer.security.MD5;
import com.hl.payServer.service.PayTradeInfoService;
import com.hl.payServer.util.DateUtil;
import com.hl.payServer.util.HttpClientUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Administrator on 2018/10/4 0004.
 */
public class Base {
    private static final Logger logger =  LoggerFactory.getLogger(Base.class);
    @Autowired
    protected PayTradeInfoService payTradeInfoService;

    public void goNotifies(PayTradeInfo p, PayTradeInfoService payTradeInfoService) {
        if (p != null && !"1".equals(p.getNotifieFlag()) && p.getNotifieCount() <= 8) {
            //在下方拼装需要通知客户端的所有参数
            sendNotifies(p, payTradeInfoService);
        }
    }

    public void sendNotifies(PayTradeInfo p, PayTradeInfoService payTradeInfoService) {
        Map map = createReturnMap(p);
        boolean isSuccess = issuedNotifies(p.getNotifieUrl(),map);
        if (isSuccess) {
            //更改库里的通知状态为已经通完毕,不用在通知了,
            // notifie_flag=1 notifie_time =now notifie_count+1
            p.setNotifieCount(p.getNotifieCount()+1);
            p.setNotifieTime(new Date());
            p.setNotifieFlag(1);
            payTradeInfoService.updateNotifieStatus(p);
        } else {
            //根据已通知次数,更新下次通知时间
            p.setNotifieTime(setNextNotifies(p.getNotifieCount()));
            p.setNotifieCount(p.getNotifieCount()+1);
            payTradeInfoService.updateNotifieStatus(p);
        }
    }

    /**
     * 拼装需要通知客户端的所有参数  签名在发送之前自动签 和随机数
     * @param p
     * @return
     */
    private Map createReturnMap(PayTradeInfo p) {
        Map<String,String> map = new HashMap<String,String>();
        map.put("companyCode", p.getCompanyCode());
        map.put("tradeType", p.getTradeType());
        map.put("payChannle", p.getPayChannle()+"");
        map.put("bizNo", p.getBizNo());
        map.put("tradeNo", p.getTradeNo());
        map.put("outTradeNo", p.getOutTradeNo());//第三方支付单号，微信或支付宝的单号
        map.put("totalFee", p.getAmount()+"");
        map.put("totalFee_fen", p.getAmount()+"");//金钱单位 分为单位的  为了解决银行表和三方支付表存的单位不同问题
        map.put("totalFee_yuan", new BigDecimal(p.getAmount()).divide(BigDecimal.valueOf(100))+"");//金额单位 元为单位的  为了解决银行表和三方支付表存的单位不同问题
        map.put("payTime", p.getPayTime()==null?"":DateUtil.turnDateToString(p.getPayTime(),"yyyy-MM-dd HH:mm:ss"));
        map.put("status", p.getStatus()+"");
        map.put("backup1", p.getBackup1());
        map.put("backup2", p.getBackup2());
        map.put("backup3", p.getBackup3());
        map.put("backup4", p.getBackup4());
        map.put("backup5", p.getBackup5());
        map.put("projectCode", p.getProjectCode());
        map.put("body", p.getBody());
        map.put("nonce_str", UUID.randomUUID()+"");
        return map;
    }

    /**
     * 计算下次通知时间
     * @param count 为修改之前的通知次数
     * @return
     */
    private final static int[] seconds = new int[]{15,15,30,180,1800,1800,1800,1800,3600};
    public Date setNextNotifies(int count){
        if (count <= 8) {
            return DateUtil.getTimeBySecond(new Date(), seconds[count]);
        }
        return null;
    }

    /**
     * 通知下发方法
     * @param url
     * @param map
     * @return
     */
    public boolean issuedNotifies(String url,Map map){
        if (map == null) {
            map = new HashMap();
        }
        map.put("sign", getSign(map));//制作签名
        Map params = new HashMap();
        params.put("data", JSON.toJSONString(map));
        String result = null;
        try {
            logger.error("通知交易中心:"+ JSON.toJSONString(params));
            result = HttpClientUtils.post(url, params, null, 10000, 10000);
        } catch (Exception e) {
            logger.error("通知下发方法异常", e);
            return false;
        }
        return result != null && result.toUpperCase().equals("SUCCESS");
    }

    /**
     * 加密规则 取所有参数列表除sign字段外 按key排序后,将所有值拼接在一起后,加入双方约定字符串后转 32位大写MD5相互较验
     * @param paramMap
     * @return
     */
    public String getSign(Map paramMap){
        Map paramTreeMap = new TreeMap(paramMap);
        StringBuffer sb = new StringBuffer();
        /**取传来的参数Map集合值组合成规则加密MD5 **/
        for (Iterator iterator = paramTreeMap.keySet().iterator(); iterator.hasNext();) {
            String key = (String) iterator.next();
            if (!"sign".equals(key)) {
                if (paramTreeMap.get(key) != null && !"".equals(paramTreeMap.get(key))) {
                    sb.append(paramTreeMap.get(key));
                }
            }
        }
        sb.append("hl_pay");
        return MD5.generate(sb.toString(), false).toUpperCase();
    }
}
